﻿using System;
using System.Diagnostics.Contracts;
using AnthStat.Infrastructure.Statistics;

namespace AnthStat.Domain
{
    public sealed class ResultsCDC : IResults
    {
        public event EventHandler ScoresUpdated;

        public Measurement Measurement { get; private set; }

        public double? BMIForAgeZ { get; set; }
        public double? BMIForAgeP { get; set; }

        public double? HeadCircumferenceForAgeZ { get; set; }
        public double? HeadCircumferenceForAgeP { get; set; }

        public double? StatureForAgeZ { get; set; }
        public double? StatureForAgeP { get; set; }

        public double? WeightForStatureZ { get; set; }
        public double? WeightForStatureP { get; set; }

        public double? WeightForAgeZ { get; set; }
        public double? WeightForAgeP { get; set; }

        public ResultsCDC(Measurement measurement)
        {
            Contract.Requires(measurement != null);

            this.Measurement = measurement;
        }

        public void CalculateScores()
        {
            // Get z-scores

            double ageDays = Measurement.AgeDays;
            double ageMonths = Measurement.AgeMonths;
            double? bmi = Measurement.BodyMassIndex;
            double? height = Measurement.Height;
            double? weight = Measurement.Weight;
            double? headCircumference = Measurement.HeadCircumference;
            
            // flags
            double bmiFlag = 0;
            double haFlag = 0;
            double waFlag = 0;
            double whFlag = 0;
            double headCircumFlag = 0;

            int sex = 1; // male

            if (Measurement.Person.Sex.Equals(Sex.Female))
            {
                sex = 2; // female
            }

            if (bmi.HasValue && !Double.IsNaN(bmi.Value))
            {
                BMIForAgeZ = CDC2000.GetZScore(Indicator.BMIForAge, bmi.Value, ageMonths, sex, ref bmiFlag);
            }
            else
            {
                BMIForAgeZ = null;
            }

            if (height.HasValue && !Double.IsNaN(height.Value))
            {
                StatureForAgeZ = CDC2000.GetZScore(Indicator.HeightForAge, height.Value, ageMonths, sex, ref haFlag);
            }
            else
            {
                StatureForAgeZ = null;
            }

            if (weight.HasValue && !Double.IsNaN(weight.Value))
            {
                WeightForAgeZ = CDC2000.GetZScore(Indicator.WeightForAge, weight.Value, ageMonths, sex, ref waFlag);
            }
            else
            {
                WeightForAgeZ = null;
            }

            if (weight.HasValue && height.HasValue && !Double.IsNaN(weight.Value) && !Double.IsNaN(height.Value))
            {
                WeightForStatureZ = CDC2000.GetZScore(Indicator.WeightForHeight, weight.Value, height.Value, sex, ref whFlag);
            }
            else
            {
                WeightForStatureZ = null;
            }

            if (headCircumference.HasValue && !Double.IsNaN(headCircumference.Value))
            {
                HeadCircumferenceForAgeZ = CDC2000.GetZScore(Indicator.HCForAge, headCircumference.Value, ageMonths, sex, ref headCircumFlag);
            }
            else
            {
                HeadCircumferenceForAgeZ = null;
            }

            // Get p-values from z-scores

            if (BMIForAgeZ.HasValue)
            {
                BMIForAgeP = PFromZ.GetPercentile(BMIForAgeZ.Value);
            }
            else
            {
                BMIForAgeP = null;
            }

            if (HeadCircumferenceForAgeZ.HasValue)
            {
                HeadCircumferenceForAgeP = PFromZ.GetPercentile(HeadCircumferenceForAgeZ.Value);
            }
            else
            {
                HeadCircumferenceForAgeP = null;
            }

            if (StatureForAgeZ.HasValue)
            {
                StatureForAgeP = PFromZ.GetPercentile(StatureForAgeZ.Value);
            }
            else
            {
                StatureForAgeP = null;
            }

            if (WeightForStatureZ.HasValue)
            {
                WeightForStatureP = PFromZ.GetPercentile(WeightForStatureZ.Value);
            }
            else
            {
                WeightForStatureP = null;
            }

            if (WeightForAgeZ.HasValue)
            {
                WeightForAgeP = PFromZ.GetPercentile(WeightForAgeZ.Value);
            }
            else
            {
                WeightForAgeP = null;
            }

            if (ScoresUpdated != null)
            {
                ScoresUpdated(this, new EventArgs());
            }
        }
    }
}
